package com.iqiyi.pps.epg.web.timer;

import com.alibaba.fastjson.JSON;
import com.iqiyi.pps.epg.core.async.AsyncService;
import com.iqiyi.pps.epg.core.async.HeartBeatCenter;
import com.iqiyi.pps.epg.core.async.IAsyncTask;
import com.iqiyi.pps.epg.core.async.IHeartBeat;
import com.iqiyi.pps.epg.core.model.channel.ChannelLog;
import com.iqiyi.pps.epg.core.model.program.ProgramData;
import com.iqiyi.pps.epg.core.model.program.ProgramNoticeCheckData;
import com.iqiyi.pps.epg.core.service.channel.ChannelService;
import com.iqiyi.pps.epg.core.service.program.ProgramService;
import com.iqiyi.pps.epg.core.utils.ApiChatUtil;
import com.iqiyi.pps.epg.core.utils.Constants;
import com.iqiyi.pps.epg.core.utils.DateTimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by karkarrotxu on 2016/6/22.
 */
public class NoticeStartTrigger {
    private static Logger logger = LoggerFactory.getLogger(NoticeStartTrigger.class);
    private static Map<Long, ProgramNoticeCheckData> checkMap = new ConcurrentHashMap<>();
    public static final String FORMAT_PHASE3 = "参数[奇谱Id:%d,通知开始:%s]";
    public static final long BUFF_TIME = 300000L;
    @Autowired
    private ProgramService programService;
    private AsyncServiceImpl asyncService = new AsyncServiceImpl();
    @Autowired
    private ChannelService channelService;


    public void initMethod() {
        logger.info("NoticeStartTrigger initMethod");
        asyncService.init();
    }

    public void task() {
        asyncService.addQueryTask();
    }

    public boolean doSendNotice(ProgramNoticeCheckData data) {
        logger.info("[ doSendNotice start  qipuId {}]", data.getQipuId());
        StringBuffer sb = new StringBuffer();
        sb.append(String.format(FORMAT_PHASE3, data.getQipuId(), DateTimeUtil.transLongFormat(data.getStartTime())));
        if (data.getChatRoomId() < 1 || data.getChatEnable() < 1) {
            logger.info("[ skip data  {}]", JSON.toJSONString(data));
            writeChannelLog(data.getFatherId(), sb + (" ; fail : 聊天室未启用 ;" +
                    "\n: detailInfo: {roomId=" + data.getChatRoomId() + ",chatEnable:" + (data.getChatEnable() > 0) + " }"));
            return true;
        }
        long retValue = ApiChatUtil.doSysNoticeStart(data.getChatRoomId(), data.getQipuId(), ApiChatUtil.DEFAULT_ICON);
        writeChannelLog(data.getFatherId(), sb + (retValue > -1 ? "success" : "fail"));
        return retValue > -1;
    }

    private void writeChannelLog(long channelId, String descr) {
        try {
            ChannelLog channelLog = new ChannelLog();
            channelLog.setFatherId(channelId);
            channelLog.setDescr(descr);
            channelLog.setType(Constants.LogType.SEND_NOTICE_START.getIndex());
            channelLog.setUser(Constants.SYSTEM_USER_SIGN);
            channelService.saveLog(channelLog);
        } catch (Exception e) {
            logger.error("writeChannelLog", e);
        }
    }


    public class AsyncServiceImpl extends AsyncService implements IHeartBeat {
        private final static int HEARTBEAT_DELAY = 1000; //

        private long heartBeatTime = 0;
        private List<ProgramNoticeCheckData> checkList = null;
        protected boolean queryEnable() {
            return getEnable("notice");
        }
        @Override
        public void tick(long now) {
            if (now - heartBeatTime >= HEARTBEAT_DELAY) {
                heartBeatTime = now;
                if (checkList == null || checkList.size() == 0) {
                    return;
                }
                this.accept(new IAsyncTask() {
                    @Override
                    public void doTask() {
                        doCheckTask();
                    }
                });
            }
        }

        public void addQueryTask() {
            this.accept(new IAsyncTask() {
                @Override
                public void doTask() {
                    logger.info("task start");
                    asyncService.doQueryTask();
                    logger.info("task end");
                }
            });
        }

        public void init() {
            HeartBeatCenter.add(this);
        }

        public void doQueryTask() {
            try {
                boolean hasModify = false;
                long checkStartTime = System.currentTimeMillis();
                long minStartTime = checkStartTime - BUFF_TIME;
                long maxStartTime = checkStartTime + BUFF_TIME;
                List<ProgramData> list = programService.doQueryNoticeStart(minStartTime, maxStartTime);

                logger.info("list.size={}", list.size());
                if (list.size() > 0) {
                    ProgramNoticeCheckData checkData = null;
                    for (ProgramData p : list) {
                        if (!checkMap.containsKey(p.getId())) {
                            checkData = new ProgramNoticeCheckData();
                            checkData.setId(p.getId());
                            checkData.setQipuId(p.getQipuId());
                            checkData.setFatherId(p.getFatherId());
                            checkData.setChatRoomId(p.getChatRoomId());
                            checkData.setChatEnable(p.getChatEnable());
                            checkData.initByNoticeStartTime(p.getNoticeStartTime().getTime());
                            checkMap.put(checkData.getId(), checkData);
                            logger.info("[add to queue pid={},qipuId={}]", p.getId(), p.getQipuId());
                        } else {
                            checkData = checkMap.get(p.getId());
                            hasModify = p.getChatRoomId() != checkData.getChatRoomId() || checkData.getStartTime() != p.getNoticeStartTime().getTime() ||
                                    p.getChatEnable() != checkData.getChatEnable();
                            if (checkData.getStartTime() != p.getNoticeStartTime().getTime()) {
                                checkData.initByNoticeStartTime(p.getNoticeStartTime().getTime());
                            }
                            checkData.setChatRoomId(p.getChatRoomId());
                            checkData.setChatEnable(p.getChatEnable());
                            if (hasModify) {
                                logger.info("[update queue {}]", JSON.toJSONString(checkData));
                            }
                        }
                    }
                }
                List<ProgramNoticeCheckData> checkList = new ArrayList<>(checkMap.values());
                asyncService.startTask(checkList);
            } catch (Exception e) {
                logger.error("[NoticeStartTrigger][doQueryTask]", e);
            }
        }

        public void setList(List<ProgramNoticeCheckData> list) {
            this.checkList = list;
        }

        public void startTask(final List<ProgramNoticeCheckData> list) {
            if (list.size() == 0) {
                return;
            }
            this.accept(new IAsyncTask() {
                @Override
                public void doTask() {
                    logger.info("start new Task ");
                    asyncService.setList(list);
                    logger.info("start new Task end");
                }
            });
        }

        private void doCheckTask() {
            long checkStartTime = System.currentTimeMillis();
            List<Long> removeList = new ArrayList<Long>();
            logger.info("[AsyncService][doCheckTask]start");
            for (ProgramNoticeCheckData temp : checkList) {
                ProgramNoticeCheckData.STATUS status = temp.getCheckStatus(checkStartTime);
                switch (status) {
                    case PHASE_OVER_CHECK:
                        removeList.add(temp.getId());
                        break;
                    case PHASE_SEND:
                        if (doSendNotice(temp)) {
                            temp.setLastExcuteTime(checkStartTime);
                        }
                        break;
                    case IN_WAIT:
                        break;
                }
            }
            ProgramNoticeCheckData removedObj = null;
            if (removeList.size() > 0) {
                logger.info("[NoticeStartTrigger][task]remove " + removeList.toString());
                for (Long removeId : removeList) {
                    removedObj = checkMap.remove(removeId);
                    if (removedObj != null) {
                        checkList.remove(removedObj);
                        logger.info("checkList remove :" + removedObj.getId());
                    }
                }
            }
            logger.info("[AsyncService][doCheckTask]end");
        }

    }
}
